今天,我們將學習 Rust 的一些進階特性,包括不安全 Rust、進階特徵和型別系統的更多細節。
不安全 Rust 允許我們執行一些在安全 Rust 中被禁止的操作。但這也意味著程式設計師需要自行確保記憶體安全。
在不安全區塊中,我們可以:
fn main() {
let mut num = 5;
let r1 = &num as *const i32;
let r2 = &mut num as *mut i32;
unsafe {
println!("r1 指向的值:{}", *r1);
*r2 += 1;
println!("r2 修改後的值:{}", *r2);
}
}
關聯型別 允許我們在特徵定義中指定佔位型別。
trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
}
struct Counter {
count: u32,
}
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
self.count += 1;
if self.count < 6 {
Some(self.count)
} else {
None
}
}
}
fn main() {
let mut counter = Counter { count: 0 };
println!("{:?}", counter.next());
println!("{:?}", counter.next());
}
我們可以為泛型型別參數指定預設型別。
use std::ops::Add;
#[derive(Debug, PartialEq)]
struct Point {
x: i32,
y: i32,
}
impl Add for Point {
type Output = Point;
fn add(self, other: Point) -> Point {
Point {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
fn main() {
assert_eq!(Point { x: 1, y: 0 } + Point { x: 2, y: 3 },
Point { x: 3, y: 3 });
}
新型別模式允許我們創建一個封裝了另一個型別的新型別。
struct Kilometers(f64);
impl Kilometers {
fn to_miles(&self) -> f64 {
self.0 * 0.621371
}
}
fn main() {
let distance = Kilometers(100.0);
println!("{}公里等於{}英里", distance.0, distance.to_miles());
}
型別別名讓我們可以為已存在的型別建立另一個名稱。
type Thunk = Box<dyn Fn() + Send + 'static>;
let f: Thunk = Box::new(|| println!("嗨"));
fn takes_long_type(f: Thunk) {
// --省略--
}
fn returns_long_type() -> Thunk {
// --省略--
Box::new(|| ())
}
!
)Never 型別(!
)代表一個永不返回的計算。
fn bar() -> ! {
panic!("這個函式永不返回!");
}
fn main() {
let guess: u32 = match "3".parse() {
Ok(num) => num,
Err(_) => {
println!("無法解析數字");
return; // 這裡的 return 的型別是 `!`
}
};
println!("猜測的數字是:{}", guess);
}
讓我們來實現一個簡單的記憶體池,它使用不安全的 Rust 來管理記憶體,但對外提供安全的介面。
use std::alloc::{alloc, dealloc, Layout};
use std::marker::PhantomData;
use std::mem;
use std::ptr::NonNull;
struct MemoryPool<T> {
data: NonNull<T>,
capacity: usize,
_marker: PhantomData<T>,
}
impl<T> MemoryPool<T> {
pub fn new(capacity: usize) -> Self {
let layout = Layout::array::<T>(capacity).unwrap();
let data = unsafe { NonNull::new(alloc(layout) as *mut T).unwrap() };
MemoryPool { data, capacity, _marker: PhantomData }
}
pub fn allocate(&self, value: T) -> Option<NonNull<T>> {
if self.capacity == 0 {
return None;
}
unsafe {
let ptr = self.data.as_ptr().add(self.capacity - 1);
ptr.write(value);
Some(NonNull::new_unchecked(ptr))
}
}
}
impl<T> Drop for MemoryPool<T> {
fn drop(&mut self) {
let layout = Layout::array::<T>(self.capacity).unwrap();
unsafe {
dealloc(self.data.as_ptr() as *mut u8, layout);
}
}
}
fn main() {
let pool = MemoryPool::<i32>::new(5);
let ptr = pool.allocate(42).unwrap();
unsafe {
println!("分配的值:{}", *ptr.as_ptr());
}
}
明天,我們將學習 Rust 的模組系統、套件管理和測試,對組織更大型的 Rust 專案並確保程式碼品質有很大的幫助。